package org.example.service.impl;

import cn.hutool.core.util.IdUtil;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import io.appium.java_client.AppiumBy;
import io.appium.java_client.android.options.UiAutomator2Options;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.StatObjectArgs;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import jakarta.annotation.Resource;
import org.example.config.MinioConfig;
import org.example.service.FileService;
import org.example.service.core.AppiumExecute;
import org.example.utils.FileUtil;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class FileServiceImpl implements FileService {

    @Resource
    private MinioConfig minioConfig;
    @Resource
    private MinioClient minioClient;

    @Resource
    private UiAutomator2Options options;

    @Override
    public String upload(MultipartFile file) {
        String fileName = FileUtil.getFileName(file.getOriginalFilename());

        new Thread(() -> {
            uploadFile(file, fileName);
        }).start();

        return minioConfig.getEndpoint() + "/" + minioConfig.getBucketName() + "/" + fileName;
        //TODO  URL需要保存在数据库中

    }

    public void uploadFile(MultipartFile file, String fileName) {
        if (file == null || file.getSize() == 0) {
            throw new RuntimeException("文件为空");
        } else {
            InputStream fileInputStream = null;
            try {
                fileInputStream = file.getInputStream();

                minioClient.putObject(PutObjectArgs.builder().bucket(minioConfig.getBucketName())
                        .object(fileName)
                        .stream(fileInputStream, file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build());
            } catch (Exception e) {
                throw new RuntimeException("文件上传失败");
            }
        }
    }


    /**
     * 获取指定远程文件的临时URL。
     *
     * @param remotefilePath 远程文件的路径。
     * @return 返回该文件的临时URL，该URL在一定时间内有效。
     * @throws RuntimeException 如果获取临时URL失败，则抛出运行时异常。
     */
    public String getTempFileUrl(String remotefilePath) {

        try {
            // 从远程文件路径中提取文件名
            String fileName = remotefilePath.substring(remotefilePath.lastIndexOf("/") + 1);
            // 构建获取预签名对象URL的参数
            GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
                    .bucket(minioConfig.getBucketName()) // 指定存储桶名称
                    .object(fileName) // 指定对象（文件）名
                    .expiry(10, TimeUnit.MINUTES) // 设置URL过期时间为1分钟
                    .method(Method.GET) // 设置请求方法为GET
                    .build();

            // 调用MinIO服务获取预签名的文件URL
            String presignedObjectUrl = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);

            return presignedObjectUrl;
        } catch (Exception e) {
            // 若遇到异常，则抛出运行时异常，并附带错误信息
            throw new RuntimeException("获取临时文件链接失败");

        }


    }

    /**
     * 将远程文件复制到本地临时文件。
     *
     * @param remoteFilePath 远程文件路径
     * @return 本地临时文件的路径
     * @throws RuntimeException 如果复制过程失败，则抛出运行时异常
     */
    @Override
    public String copyRemoteFileToLocalTmpFile(String remoteFilePath) {
        // 构建本地临时文件路径
        String localTmpFilePath = System.getProperty("user.dir") + File.separator + "static" + File.separator
                + IdUtil.simpleUUID() +
                FileUtil.getSuffix(remoteFilePath);

        // 创建本地临时文件的目录
        FileUtil.mkdir(localTmpFilePath);

        try {
            // 获取远程文件的临时URL
            String tempFileUrl = getTempFileUrl(remoteFilePath);

            // 从URL打开输入流
            URL url = new URL(tempFileUrl);
            InputStream inputStream = url.openStream();

            // 指定本地文件的路径
            Path path = Path.of(localTmpFilePath);

            // 将输入流中的数据复制到本地文件，如果文件已存在，则替换
            Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING);

            // 关闭输入流
            inputStream.close();

            // 返回本地文件的路径
            return path.toFile().getPath();
        }catch (Exception e){
            // 如果过程中出现异常，则抛出运行时异常
            throw new RuntimeException(e);
        }

    }

    @Override
    public boolean doesObjectExist(MinioClient minioClient, String bucketName, String objectName) {
        boolean flag = false;
        try {
            minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
            return true; // 如果执行到这里，说明对象存在
        } catch (Exception e) {
            return flag;
//            throw new RuntimeException(e);
        }
    }

    /*
    根据链接下载apk

    1.下载apk
    2.上传到minio
     */
    @Override
    public String linkAndUpload(String link) {
//        long l1 = System.currentTimeMillis();
        String fileName = UUID.randomUUID().toString().replaceAll("-", "") + ".apk"; // 自定义保存的文件名
//        String saveDir = System.getProperty("user.dir") + File.separator + fileName; // 设置保存文件的目录，这里假设是当前目录


        try {
            // 从 URL 下载 APK 文件
            URL url = new URL(link);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            InputStream inputStream = connection.getInputStream();

            // 上传 APK 文件到 MinIO
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(minioConfig.getBucketName()) // 指定存储桶名称
                            .object(fileName) // 指定对象（文件）名
                            .stream(inputStream, connection.getContentLengthLong(), -1)
                            .contentType("application/vnd.android.package-archive")
                            .build()
            );

            inputStream.close();
            connection.disconnect();

            System.out.println("APK 文件上传成功！");
        } catch (Exception e) {
            System.err.println("上传失败: " + e.getMessage());
        }

        return fileName;
    }

    @Override
    public String analysisQRcode(MultipartFile file) {
        String url = null;
        try {
            // 使用MultipartFile的getInputStream()方法获取输入流
            InputStream inputStream = file.getInputStream();
            // 读取图片
            BufferedImage image = ImageIO.read(inputStream);

            // 解析二维码
            Result result = decodeQRCode(image);
            if (result != null) {
                // 输出解析结果
                url = result.getText();
                System.out.println("解析得到的链接: " + url);

            } else {
                // 未找到有效二维码
                throw new RuntimeException("未在图片中找到有效的二维码");
            }
        } catch (IOException e) {
            // 图片读取错误
            System.err.println("读取图片时发生错误: " + e.getMessage());
        } catch (NotFoundException e) {
            // 二维码解析错误
            System.err.println("解析二维码时发生错误: " + e.getMessage());
        }
        return url;
    }

    @Override
    public String appiumWithUrl(String url) {
        AppiumExecute appiumExecute = new AppiumExecute(minioConfig, minioClient, options);
        return appiumExecute.execute(url);
    }

    private static Result decodeQRCode(BufferedImage image) throws NotFoundException {
        QRCodeReader reader = new QRCodeReader();
        // 将图片转换为二进制位图
        BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(
                new BufferedImageLuminanceSource(image)));
        // 设置解码提示信息
        Map<DecodeHintType, Object> hints = new HashMap<>();
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); // 指定字符编码为UTF-8
        try {
            // 尝试解码图片中的二维码
            return reader.decode(binaryBitmap, hints);
        } catch (Exception e) {
            // 如果解码失败，则抛出运行时异常
            throw new RuntimeException();
        }
    }

}
